#ifndef __LOGGER_HPP__
#define __LOGGER_HPP__

#include "sink.hpp"
#include "looper.hpp"
#include "formatter.hpp"
#include <iostream>
#include <sstream>
#include <mutex>
#include <atomic>
#include <unordered_map>
#include <cassert>
#include <stdarg.h>

namespace logs
{
    class Logger
    {
    public:
        using ptr = std::shared_ptr<Logger>;
        Logger(const std::string &logger_name, LogLevel::value level, Formatter::ptr &formatter, std::vector<LogSink::ptr> &sinks)
            : _name(logger_name), _level(level), _formatter(formatter), _sinks(sinks)
        {
        }

        std::string &name()
        {
            return _name;
        }

        /*完成构造日志消息对象过程并进行格式化，得到格式化的日志消息字符串---然后进行落地输出*/
        void debug(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 通过传入的参数构造出一个日志对象，进行日志格式化，最终落地
            // 1.判断当前的日志是否达到了输出等级
            if (LogLevel::value::DEBUG < _level)
                return;
            // 2.对格式化字符串fmt进行不定参的解析，得到日志消息正文（就是上层业务消息）字符串
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret < 0)
            {
                std::cout << "vasprintf failed\n";
                return;
            }
            va_end(ap);
            serialize(LogLevel::value::DEBUG, file, line, res);
            free(res);
        }

        void info(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 通过传入的参数构造出一个日志对象，进行日志格式化，最终落地
            // 1.判断当前的日志是否达到了输出等级
            if (LogLevel::value::INFO < _level)
                return;
            // 2.对格式化字符串fmt进行不定参的解析，得到日志消息正文（就是上层业务消息）字符串
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret < 0)
            {
                std::cout << "vasprintf failed\n";
                return;
            }
            va_end(ap);
            serialize(LogLevel::value::INFO, file, line, res);
            free(res);
        }

        void warn(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 通过传入的参数构造出一个日志对象，进行日志格式化，最终落地
            // 1.判断当前的日志是否达到了输出等级
            if (LogLevel::value::WARN < _level)
                return;
            // 2.对格式化字符串fmt进行不定参的解析，得到日志消息正文（就是上层业务消息）字符串
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret < 0)
            {
                std::cout << "vasprintf failed\n";
                return;
            }
            va_end(ap);
            serialize(LogLevel::value::WARN, file, line, res);
            free(res);
        }

        void error(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 通过传入的参数构造出一个日志对象，进行日志格式化，最终落地
            // 1.判断当前的日志是否达到了输出等级
            if (LogLevel::value::ERROR < _level)
                return;
            // 2.对格式化字符串fmt进行不定参的解析，得到日志消息正文（就是上层业务消息）字符串
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret < 0)
            {
                std::cout << "vasprintf failed\n";
                return;
            }
            va_end(ap);
            serialize(LogLevel::value::ERROR, file, line, res);
            free(res);
        }

        void fatal(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 通过传入的参数构造出一个日志对象，进行日志格式化，最终落地
            // 1.判断当前的日志是否达到了输出等级
            if (LogLevel::value::FATAL < _level)
                return;
            // 2.对格式化字符串fmt进行不定参的解析，得到日志消息正文（就是上层业务消息）字符串
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret < 0)
            {
                std::cout << "vasprintf failed\n";
                return;
            }
            va_end(ap);
            serialize(LogLevel::value::FATAL, file, line, res);
            free(res);
        }

    protected:
        /*抽象接口完成实际落地输出--不同的日志器会有不同的的实际落地方式*/
        virtual void log(const char *data, size_t len) = 0;

        void serialize(LogLevel::value level, const std::string &file, size_t line, char *str)
        {
            // 3.构造LogMsg对象
            LogMsg msg(_name, file, line, level, str);
            // 4.通过格式化工具_formatter对于LogMsg对象进行格式化，最终得到完整的日志消息字符串
            std::stringstream ss;
            _formatter->format(ss, msg);
            // 5.日志落地
            log(ss.str().c_str(), ss.str().size());
        }

    protected:
        std::mutex _mutex;                   // 互斥锁
        std::string _name;                   // 日志器名称
        std::atomic<LogLevel::value> _level; // 默认日志等级限制级别
        Formatter::ptr _formatter;           // 日志格式化器句柄
        std::vector<LogSink::ptr> _sinks;    // 多种落地方向管理集合
    };

    class AsyncLogger : public Logger
    {
    public:
        AsyncLogger(const std::string &logger_name,
                    LogLevel::value level,
                    Formatter::ptr &formatter,
                    std::vector<LogSink::ptr> &sinks,
                    AsyncType looper_type = AsyncType::ASYNC_SAFE)
            : Logger(logger_name, level, formatter, sinks), _looper(std::make_shared<AsyncLooper>(std::bind(&AsyncLogger::realLog, this, std::placeholders::_1), looper_type))
        {
        }

        void log(const char *data, size_t len) override
        {
            _looper->push(data, len);
        }

    private:
        void realLog(Buffer &buffer)
        {
            if (_sinks.empty())
                return;
            for (auto &iter : _sinks)
            {
                iter->log(buffer.begin(), buffer.readAbleSize());
            }
        }

    private:
        AsyncLooper::ptr _looper;
    };

    class SyncLogger : public Logger
    {
    public:
        SyncLogger(const std::string &logger_name, LogLevel::value level, Formatter::ptr &formatter, std::vector<LogSink::ptr> &sinks)
            : Logger(logger_name, level, formatter, sinks)
        {
        }

    protected:
        /*同步日志器，是将日志直接通过落地模块句柄进行日志落地*/
        void log(const char *data, size_t len) override
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if (_sinks.empty())
                return;
            for (auto &iter : _sinks)
            {
                iter->log(data, len);
            }
        }
    };

    /*定义日志器类型*/
    enum class LoggerType
    {
        LOGGER_SYNC,
        LOGGER_ASYNC
    };

    /*
        抽象出来的日志器建造者类
    */
    class LoggerBuilder
    {
    public:
        LoggerBuilder()
            : _logger_type(LoggerType::LOGGER_SYNC), _limit_level(LogLevel::value::DEBUG), _looper_type(AsyncType::ASYNC_SAFE)
        {
        }

        void buildLoggerType(LoggerType type) { _logger_type = type; }
        void buildEnableUnSafeAsync() { _looper_type = AsyncType::ASYNC_UNSAFE; }
        void buildLoggerName(const std::string &name) { _logger_name = name; }
        void buildLoggerLevel(LogLevel::value level) { _limit_level = level; }
        void buildFormatter(const std::string &pattern)
        {
            _formatter = std::make_shared<Formatter>(pattern);
        }

        template <class SinkType, class... Args>
        void buildSink(Args &&...args)
        {
            _sinks.push_back(SinkFactory::create<SinkType>(std::forward<Args>(args)...));
        }
        
        virtual Logger::ptr build() = 0;

    protected:
        AsyncType _looper_type;
        LoggerType _logger_type;          // 日志器类型
        std::string _logger_name;         // 日志器名称
        LogLevel::value _limit_level;     // 日志器默认级别
        Formatter::ptr _formatter;        // 日志格式化工具句柄
        std::vector<LogSink::ptr> _sinks; // 日志器落地方向集合
    };

    class LocalLoggerBuilder : public LoggerBuilder
    {
    public:
        Logger::ptr build() override
        {
            assert(_logger_name.empty() == false); // 必须要有日志器名称
            if (_formatter.get() == nullptr)
            {
                _formatter = std::make_shared<Formatter>();
            }
            if (_sinks.empty())
            {
                buildSink<StdoutSink>();
            }
            if (_logger_type == LoggerType::LOGGER_ASYNC)
            {
                return std::make_shared<AsyncLogger>(_logger_name, _limit_level, _formatter, _sinks, _looper_type);
            }
            else
            {
                return std::make_shared<SyncLogger>(_logger_name, _limit_level, _formatter, _sinks);
            }
        }
    };

    class LoggerManager
    {
    public:
        static LoggerManager &getInstance()
        {
            static LoggerManager eton;
            return eton;
        }

        void addLogger(Logger::ptr &logger)
        {
            if (hasLogger(logger->name()))
                return;
            std::unique_lock<std::mutex> lock(_mutex);
            _loggers.insert(std::make_pair(logger->name(), logger));
        }

        bool hasLogger(const std::string &logger_name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto iter = _loggers.find(logger_name);
            if (iter == _loggers.end())
                return false;
            return true;
        }

        Logger::ptr getLogger(const std::string &logger_name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto iter = _loggers.find(logger_name);
            if (iter == _loggers.end())
                return Logger::ptr();
            return iter->second;
        }

        Logger::ptr getRootLogger()
        {
            return _root_logger;
        }

    private:
        LoggerManager()
        {
            std::unique_ptr<LoggerBuilder> builder(new LocalLoggerBuilder());
            builder->buildLoggerName("root");
            _root_logger = builder->build();
            _loggers.insert(std::make_pair("root", _root_logger));
        }

    private:
        std::mutex _mutex;
        Logger::ptr _root_logger;                              // 默认日志器
        std::unordered_map<std::string, Logger::ptr> _loggers; // 日志器集合
    };

    class GlobalLoggerBuilder : public LoggerBuilder
    {
    public:
        Logger::ptr build() override
        {
            assert(_logger_name.empty() == false); // 必须要有日志器名称
            if (_formatter.get() == nullptr)
            {
                _formatter = std::make_shared<Formatter>();
            }
            if (_sinks.empty())
            {
                buildSink<StdoutSink>();
            }
            Logger::ptr logger;
            if (_logger_type == LoggerType::LOGGER_ASYNC)
            {
                logger=std::make_shared<AsyncLogger>(_logger_name, _limit_level, _formatter, _sinks, _looper_type);
            }
            else
            {
                logger=std::make_shared<SyncLogger>(_logger_name, _limit_level, _formatter, _sinks);
            }
            LoggerManager::getInstance().addLogger(logger);
            return logger;
        }
    };
}

#endif